package com.dhecp.project.common.service.impl;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.dhecp.common.core.domain.AjaxResult;
import com.dhecp.common.utils.MessageUtils;
import com.dhecp.core.constant.ModuleTableToEntity;
import com.dhecp.framework.util.ShiroUtils;
import com.dhecp.project.common.dealdata.InfoMapData;
import com.dhecp.project.common.domain.ModuleNidAndBid;
import com.dhecp.project.common.domain.UpdateFlow;
import com.dhecp.project.common.mapper.ModuleNidAndBidMapper;
import com.dhecp.project.common.service.BaseModuleService;
import com.dhecp.project.flowable.domain.SysProcessInstance;
import com.dhecp.project.flowable.mapper.SysProcessInstanceMapper;
import com.dhecp.project.flowable.service.ActProcessService;
import com.dhecp.project.flowable.service.ActProcessTaskService;
import com.dhecp.project.system.domain.SysDictionaryForModule;
import com.dhecp.project.system.service.SysDictionaryForModuleService;

/**
 * @author DH-Xxj
 * @version 2019年11月25日
 */
public class BaseModuleServiceImpl implements BaseModuleService {

//    @Autowired
//    private ModuleNidAndBidService moduleNidAndBidService;

    @Autowired
    private SysProcessInstanceMapper processInstanceMapper;

    @Autowired
    private ModuleNidAndBidMapper moduleNidAndBidMapper;

    @Autowired
    private SysDictionaryForModuleService dictionaryForModuleService;

    @Autowired
    private ActProcessService actProcessService;

    @Autowired
    private ActProcessTaskService actProcessTaskService;

    @Autowired
    private InfoMapData infoMapData;

    /**
     * 保存 - 公共基础方法
     *
     * @param moduleTable 必要参数：功能唯一标识
     * @param infoMap     必要参数：非网格字段（包括头部、底部所有显示和隐藏的字段）
     * @param infoItems   必要参数：对应实体类的json格式字符串
     * @return Map
     * @author DH-Xxj
     */
    @Override
    public AjaxResult saveDataBase(Map<String, Object> params) {
        AjaxResult ajaxResult = AjaxResult.success();
        Object businessEntity = null;
        String moduleTable = "";
        String corpNo = "";        //所属公司编码
        String corpName = "";    //所属公司
        boolean isAuto = true;
        if (params.containsKey("isAuto")) {
            isAuto = (boolean) params.get("isAuto");
        }

        if (params.get("moduleTable") == null || params.get("moduleTable") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.moduletable"));
        } else {
            moduleTable = params.get("moduleTable").toString();
        }
        if (params.get("infoMap") == null || params.get("infoMap") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.infomap"));
        }
        if (params.get("infoItems") == null || params.get("infoItems") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.infoitems"));
        }
        if (params.get("businessEntity") == null || params.get("businessEntity") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.businessentity"));
        } else {
            businessEntity = params.get("businessEntity");
        }

        Map<String, Object> infoMap = infoMapData.infoMapDeal(params.get("infoMap").toString(), params.get("moduleTable").toString());
        if (infoMap.get("enableChange") == null || (Boolean) infoMap.get("enableChange") == false) {
            return AjaxResult.warn(infoMap.get("enableChangemsg").toString());
        }
        if (infoMap.isEmpty()) {
            return AjaxResult.error(MessageUtils.message("module.error.infomapisempty"));
        } else {
            if (infoMap.get("activeFlow") == null) {
                return AjaxResult.error(MessageUtils.message("module.error.lack", "activeFlow"));
            }
//			取消本控制，以便部门流程中间环节可以保存修改
//			if (!"".equals(infoMap.get("activeFlow").toString()) && !"flowzd".equals(infoMap.get("activeFlow").toString().toLowerCase())){
//					return AjaxResult.warn(MessageUtils.message("module.warn.isflowed"));
//			}
            if (infoMap.get("procInstId") == null) {
                return AjaxResult.error(MessageUtils.message("module.error.lack", "procInstId"));
            }
            if (infoMap.get("effectStock") == null || infoMap.get("effectStock") == "" || "".equals(infoMap.get("effectStock").toString())) {
                infoMap.put("effectStock", false);
            }
            //必要时可以在此处对infoMap数据进行处理
            String nid = "0";
            if (infoMap.get("nid") != null && infoMap.get("nid") != "") {
                nid = infoMap.get("nid").toString();
            }
            if (infoMap.get("cid") != null && infoMap.get("cid") != "") {
                corpNo = infoMap.get("cid").toString();    //所属公司编码
            }
            if (infoMap.get("cidName") != null && infoMap.get("cidName") != "") {
                corpName = infoMap.get("cidName").toString(); //所属公司
            }

            if (nid.equals("0")) {
                infoMap.put("newNid", 1); //新增单据标记
//	    		ModuleNidAndBid moduleNidAndBid = moduleNidAndBidService.queryModuleNidAndBid(params);	//无事务控制，制单异常会跳过单号
                ModuleNidAndBid moduleNidAndBid = moduleNidAndBidMapper.findModuleNidAndBid(params);    //有事务控制，制单异常不跳过单号
                if (moduleNidAndBid == null) {
                    return AjaxResult.error(MessageUtils.message("module.error.ungetbid"));
                } else {
                    infoMap.put("nid", moduleNidAndBid.getNid());
                    infoMap.put("bid", moduleNidAndBid.getBid());

                    //首次保存单据时生成流程任务
                    if (isAuto) {//某些单据不需要流程
                        String moduleName = "未知功能";
                        SysDictionaryForModule dictionaryForModule = dictionaryForModuleService.queryDictionaryForModuleByModuleTable(moduleTable);
                        if (dictionaryForModule != null) {
                            if (dictionaryForModule.getModuleAlias() != null && !"".equals(dictionaryForModule.getModuleAlias())) {
                                moduleName = dictionaryForModule.getModuleAlias();
                            } else if (dictionaryForModule.getModuleName() != null && !"".equals(dictionaryForModule.getModuleName())) {
                                moduleName = dictionaryForModule.getModuleName();
                            } else {
                                moduleName = ModuleTableToEntity.queryEntityByModuleTable(moduleTable).get("moduleName").toString();
                            }
                        } else {
                            moduleName = ModuleTableToEntity.queryEntityByModuleTable(moduleTable).get("moduleName").toString();
                        }

                        SysProcessInstance sysProcessInstance = new SysProcessInstance();
                        String processTitle = moduleName + "(" + moduleNidAndBid.getBid() + ")";
                        String procDefKey = moduleTable;
                        String tableDataId = moduleNidAndBid.getNid().toString();
                        sysProcessInstance.setProcessTitle(processTitle);
                        sysProcessInstance.setProcDefKey(procDefKey);
                        sysProcessInstance.setTableDataId(tableDataId);
                        sysProcessInstance.setProcessRemark(dealProcessRemark(moduleTable, infoMap));
                        sysProcessInstance.setCorpNo(corpNo);
                        sysProcessInstance.setCorpName(corpName);
                        ajaxResult = actProcessService.startProcess(sysProcessInstance);
                        if ("0".equals(ajaxResult.get("code").toString())) {
                            if ("flowzd".equals(sysProcessInstance.getNextActAlias().toString().toLowerCase())) {
                                infoMap.put("activeFlow", sysProcessInstance.getNextActAlias().toString());
                                infoMap.put("procInstId", sysProcessInstance.getProcInstId());
                                //插入指定单据流转各环节审批人记录
                                Map<String, Object> flowRecord = new HashMap<String, Object>();
                                flowRecord.put("moduleTable", moduleTable);
                                flowRecord.put("nid", tableDataId);
                                flowRecord.put("activeFlowOld", sysProcessInstance.getNextActAlias());
                                flowRecord.put("activeFlow", sysProcessInstance.getNextActAlias());
                                flowRecord.put("activeFlowName", sysProcessInstance.getNextActAlias());
                                flowRecord.put("procInstId", sysProcessInstance.getProcInstId());
                                flowRecord.put("createUser", ShiroUtils.getMandatorId());
                                flowRecord.put("createUserName", ShiroUtils.getMandatorName());
                                flowRecord.put("updateUsers", ShiroUtils.getMandatorId());
                                flowRecord.put("optType", "add");
                                processInstanceMapper.insertProcessInstanceFlowRecord(flowRecord);
                            } else {
                                throw new RuntimeException(MessageUtils.message("flowable.model.error.modelflowzdfail"));
                            }
                        } else {
                            return ajaxResult;
                        }
                    } else {
                        infoMap.put("activeFlow", "FlowZd");
                    }
                }
            } else {    //修改保存
                if (isAuto) {
                    ajaxResult = actProcessService.updateSysProcessToBusinessData(nid, dealProcessRemark(moduleTable, infoMap), corpNo, corpName);
                    if (!"0".equals(ajaxResult.get("code").toString())) {
                        return ajaxResult;
                    }
                }

            }
        }

        List<?> businessDataList = JSON.parseArray(params.get("infoItems").toString(), businessEntity.getClass());
        if (businessDataList == null || businessDataList.size() == 0) {
            //删除单据时，先删除未完成的流程任务
            String procInstId = infoMap.get("procInstId").toString();
            if (procInstId != null && !"".equals(procInstId)) {
                ajaxResult = actProcessService.deleteProcess(procInstId);
                //插入指定单据流转各环节审批人记录（单据删除记录）
                Map<String, Object> flowRecord = new HashMap<String, Object>();
                flowRecord.put("moduleTable", moduleTable);
                flowRecord.put("nid", infoMap.get("nid"));
                flowRecord.put("activeFlowOld", "FlowZd");
                flowRecord.put("procInstId", procInstId);
                flowRecord.put("createUser", ShiroUtils.getMandatorId());
                flowRecord.put("createUserName", ShiroUtils.getMandatorName());
                flowRecord.put("updateUsers", "实际删除操作人： " + ShiroUtils.getUserName() + "【" + ShiroUtils.getUserId() + "】");
                flowRecord.put("optType", "delete");
                processInstanceMapper.insertProcessInstanceFlowRecord(flowRecord);
            }
        }
        //必要时可以在此处对businessDataList数据进行处理

        ajaxResult.put("infoMap", infoMap);
        ajaxResult.put("businessDataList", businessDataList);

        return ajaxResult;
    }

    /**
     * 大数据分批保存 - 公共基础方法
     *
     * @param moduleTable 必要参数：功能唯一标识
     * @param infoMap     必要参数：非网格字段（包括头部、底部所有显示和隐藏的字段）
     * @param infoItems   必要参数：对应实体类的json格式字符串
     * @return Map
     * @author DH-Xxj
     */
    @Override
    public AjaxResult saveBigDataBase(Map<String, Object> params) {
        AjaxResult ajaxResult = AjaxResult.success();
        Object businessEntity = null;

        if (params.get("moduleTable") == null || params.get("moduleTable") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.moduletable"));
        }
        if (params.get("infoMap") == null || params.get("infoMap") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.infomap"));
        }
        if (params.get("infoItems") == null || params.get("infoItems") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.infoitems"));
        }
        if (params.get("businessEntity") == null || params.get("businessEntity") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.businessentity"));
        } else {
            businessEntity = params.get("businessEntity");
        }

        Map<String, Object> infoMap = infoMapData.infoMapDeal(params.get("infoMap").toString(), params.get("moduleTable").toString());
        if (infoMap.get("enableChange") == null || (Boolean) infoMap.get("enableChange") == false) {
            return AjaxResult.warn(infoMap.get("enableChangemsg").toString());
        }
        if (infoMap.isEmpty()) {
            return AjaxResult.error(MessageUtils.message("module.error.infomapisempty"));
        }

        List<?> businessDataList = JSON.parseArray(params.get("infoItems").toString(), businessEntity.getClass());
        //必要时可以在此处对businessDataList数据进行处理

        ajaxResult.put("infoMap", infoMap);
        ajaxResult.put("businessDataList", businessDataList);

        return ajaxResult;
    }

    /**
     * 流程处理公共方法，返回单据（流转、回退等）后的流程状态信息
     *
     * @param params
     * @param optType 必要参数：流程操作类型（流转：go，退回：back，驳回：reject，重置：reset）
     * @return UpdateFlow
     * @author DH-Xxj
     */
    @SuppressWarnings("unchecked")
    @Override
    public UpdateFlow FlowDealBase(Map<String, Object> params) {
        String optType = "optType";
        String activeFlowOld = "";
        AjaxResult ajaxResult = AjaxResult.success();
        UpdateFlow updateFlow = new UpdateFlow();
        Date updateTime = new Date();
        Boolean effectStock = false;
        String activeFlow = "unknown";
        String procInstId = "unknown";

        if (params.get("optType") != null && params.get("optType") != "") {
            optType = params.get("optType").toString();
        }

        if (params.get("activeFlowOld") == null || params.get("activeFlowOld") == "") {
            throw new RuntimeException("当前环节流程状态不明确，请重新打开单据再试。");
        } else {
            activeFlowOld = params.get("activeFlowOld").toString().toLowerCase();
            if ("flowzd".equals(activeFlowOld)) {
                //制单状态流程可操作性验证
                if (!"go".equals(optType)) {
                    throw new RuntimeException(MessageUtils.message("module.warn.isflowzd"));
                }
            }
            if (!"flowzd".equals(activeFlowOld)) {
                //非制单状态流程可操作性验证
            }
            if ("end".equals(activeFlowOld)) {
                //结束状态流程可操作性验证
                if ("go".equals(optType)) {
                    throw new RuntimeException(MessageUtils.message("module.warn.isflowfinished"));
                }
                if ("back".equals(optType) || "reject".equals(optType)) {
                    throw new RuntimeException(MessageUtils.message("module.warn.isflowfinished.disableback"));
                }
            }
            if (!"end".equals(activeFlowOld)) {
                //非结束状态流程可操作性验证
                if ("reset".equals(optType)) {
                    throw new RuntimeException(MessageUtils.message("module.warn.isnotend"));
                }
            }
        }

        if ("go".equals(optType)) {
            ajaxResult = updateFlowGoBase(params);    //调用公共方法--流转
            if (!"0".equals(ajaxResult.get("code").toString())) {
                throw new RuntimeException(ajaxResult.get("msg").toString());
            }
            if (ajaxResult.get("data") == null || ajaxResult.get("data") == "") {
                throw new RuntimeException(MessageUtils.message("module.error.lack", "下一环节流程状态【activeFlow】"));
            }
            activeFlow = ajaxResult.get("data").toString();
            if ("end".equals(activeFlow)) {
                effectStock = true;
            }
        } else if ("back".equals(optType) || "reject".equals(optType)) {
            ajaxResult = updateFlowBackBase(params);    //调用公共方法--退回/驳回
            if (!"0".equals(ajaxResult.get("code").toString())) {
                throw new RuntimeException(ajaxResult.get("msg").toString());
            }
            if (ajaxResult.get("data") == null || ajaxResult.get("data") == "") {
                throw new RuntimeException(MessageUtils.message("module.error.lack", "下一环节流程状态【activeFlow】"));
            }
            activeFlow = ajaxResult.get("data").toString();
        } else if ("reset".equals(optType)) {
            ajaxResult = updateFlowResetBase(params);    //调用公共方法--重置流程
            if (!"0".equals(ajaxResult.get("code").toString())) {
                throw new RuntimeException(ajaxResult.get("msg").toString());
            }
            if (ajaxResult.get("data") == null || ajaxResult.get("data") == "") {
                throw new RuntimeException(MessageUtils.message("module.error.lack", "重置流程实例ID【procInstId】"));
            }
            activeFlow = "FlowZd";
            procInstId = ajaxResult.get("data").toString();
            updateFlow.setProcInstId(procInstId);    //重置操作生成新的流程实例
        } else if ("resetback".equals(optType)) {//重置回退
            ajaxResult = updateFlowResetBack(params);    //调用公共方法--重置回退
            if (!"0".equals(ajaxResult.get("code").toString())) {
                throw new RuntimeException(ajaxResult.get("msg").toString());
            }
            if (ajaxResult.get("data") == null) {
                throw new RuntimeException(MessageUtils.message("module.error.lack", "重置回退对象【procInstId/activeFlow】"));
            }
            Map<String, Object> backPrams = null;
            try {
                backPrams = (Map<String, Object>) ajaxResult.get("data");
            } catch (Exception ex) {
                throw new RuntimeException(MessageUtils.message("module.error.lack", "重置回退对象转换出错"));
            }
            procInstId = backPrams.get("procInstId").toString();
            activeFlow = backPrams.get("activeFlow").toString();
            updateFlow.setProcInstId(procInstId);
        } else {
            throw new RuntimeException("流程操作类型[" + optType + "]无效，可用取值为（流转：go，退回：back，驳回：reject，重置：reset）");
        }

        //插入指定单据流转各环节审批人记录
        Map<String, Object> flowRecord = new HashMap<String, Object>();
        String moduleTable = "";
        String tableDataId = "";
        String assignees = "";
        if (params.get("moduleTable") != null && params.get("moduleTable") != "") {
            moduleTable = params.get("moduleTable").toString();
        }
        if (params.get("tableDataId") != null && params.get("tableDataId") != "") {
            tableDataId = params.get("tableDataId").toString();
        }
        if (params.get("assignees") != null && params.get("assignees") != "") {
            assignees = params.get("assignees").toString();
        }
        flowRecord.put("moduleTable", moduleTable);
        flowRecord.put("nid", tableDataId);
        flowRecord.put("activeFlowOld", activeFlowOld);
        flowRecord.put("activeFlow", activeFlow);
        flowRecord.put("activeFlowName", activeFlow);
        flowRecord.put("procInstId", procInstId);    //重置状态时生成新的流程ID，其它状态为默认值“unknown”（存储过程处理时unknown更新为单据当前流程ID）。
        flowRecord.put("createUser", ShiroUtils.getMandatorId());
        flowRecord.put("createUserName", ShiroUtils.getMandatorName());
        flowRecord.put("updateUsers", assignees);
        flowRecord.put("optType", optType);
        processInstanceMapper.insertProcessInstanceFlowRecord(flowRecord);

        updateFlow.setUpdateTime(updateTime);
        updateFlow.setEffectStock(effectStock);
        updateFlow.setActiveFlow(activeFlow);
        updateFlow.setActiveType(optType);
        updateFlow.setActiveUser(ShiroUtils.getUserId());
        updateFlow.setActiveUserName(ShiroUtils.getUserName());
        return updateFlow;
    }

    /**
     * 流转 - 公共基础方法
     *
     * @param moduleTable 必要参数：功能唯一标识
     * @param infoMap     必要参数：非网格字段（包括头部、底部所有显示和隐藏的字段）
     * @param infoItems   必要参数：对应实体类的json格式字符串（仅需 guid）
     * @return AjaxResult
     * @author DH-Xxj
     */
    @Override
    public AjaxResult updateFlowGoBase(Map<String, Object> params) {
        AjaxResult ajaxResult = AjaxResult.success();

        if (params.get("moduleTable") == null || params.get("moduleTable") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.moduletable"));
        }

        //调用流程
        String taskId = params.get("taskId").toString();
        Integer priority = Integer.valueOf(params.get("priority").toString());
        String comment = params.get("comment").toString();
        String assigneesStr = params.get("assignees").toString();
        String[] assignees1 = assigneesStr.split(",");
        List<String> assignees = Arrays.asList(assignees1);
        String medium = params.get("medium").toString();
        ajaxResult = actProcessTaskService.passProcess(taskId, priority, comment, assignees, null, medium, "web");
        return ajaxResult;
    }

    /**
     * 退回 - 公共基础方法
     *
     * @param moduleTable 必要参数：功能唯一标识
     * @param infoMap     必要参数：非网格字段（包括头部、底部所有显示和隐藏的字段）
     * @param infoItems   必要参数：对应实体类的json格式字符串（仅需 guid）
     * @return AjaxResult
     * @author DH-Xxj
     */
    @Override
    public AjaxResult updateFlowBackBase(Map<String, Object> params) {
        AjaxResult ajaxResult = AjaxResult.success();
        if (params.get("moduleTable") == null || params.get("moduleTable") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.moduletable"));
        }

        //调用流程
        String taskId = params.get("taskId").toString();
        Integer priority = Integer.valueOf(params.get("priority").toString());
        String comment = params.get("comment").toString();
        String assigneesStr = params.get("assignees").toString();
        String[] assignees1 = assigneesStr.split(",");
        List<String> assignees = Arrays.asList(assignees1);
        String medium = params.get("medium").toString();
        String optType = "back";    //退回操作(back)，驳回操作(reject)
        String activityId = "";
        if (params.get("optType") != null && params.get("optType") != "") {
            optType = params.get("optType").toString().toLowerCase();
        }
        if (params.get("activityId") != null && params.get("activityId") != "") {
            activityId = params.get("activityId").toString();
        }
        if ("back".equals(optType)) {
            ajaxResult = actProcessTaskService.backProcess(taskId, priority, comment, assignees, null, medium, "web");
        } else {
            ajaxResult = actProcessTaskService.rejectProcess(taskId, activityId, priority, comment, assignees, null, medium, "web");
        }
        return ajaxResult;
    }

    /**
     * 重置流程 - 公共基础方法
     *
     * @param nid 必要参数：单据编码
     * @return AjaxResult
     * @author DH-Xxj
     */
    @Override
    public AjaxResult updateFlowResetBase(Map<String, Object> params) {
        AjaxResult ajaxResult = AjaxResult.success();
        if (params.get("nid") == null || params.get("nid") == "") {
            return AjaxResult.error(MessageUtils.message("module.error.lack.nid"));
        }
        String nid = params.get("nid").toString();
        ajaxResult = actProcessService.resetProcess(nid);
        return ajaxResult;
    }

    @Override
    public AjaxResult updateFlowResetBack(Map<String, Object> params) {
        AjaxResult ajaxResult = AjaxResult.success();
        //调用流程
        String nid = params.get("nid").toString();
        Integer priority = Integer.valueOf(params.get("priority").toString());
        String comment = params.get("comment").toString();
        String assigneesStr = params.get("assignees").toString();
        String[] assignees1 = assigneesStr.split(",");
        List<String> assignees = Arrays.asList(assignees1);
        String medium = params.get("medium").toString();
        String activityId = "";
        if (params.get("activityId") != null && params.get("activityId") != "") {
            activityId = params.get("activityId").toString();
        }
        ajaxResult = actProcessTaskService.resetBackProcess(nid, activityId, priority, comment, assignees, medium, "web");
        return ajaxResult;
    }

    /**
     * 流程摘要，在流程任务中显示
     *
     * @param moduleTable
     * @param infoMap
     * @return processRemark
     * @author DH-Xxj
     */
    public String dealProcessRemark(String moduleTable, Map<String, Object> infoMap) {
        String processRemark = "";

        switch (moduleTable.toUpperCase()) {

            default:
                break;
        }
        if (infoMap.get("vZdbz") != null && infoMap.get("vZdbz") != "" && !"".equals(infoMap.get("vZdbz").toString())) {
            processRemark = processRemark + "备注：" + infoMap.get("vZdbz").toString();
        }
        return processRemark;
    }

}
